ASP.NET comes with a small set of built-in HTTP
handlers. There is a handler to serve ASP.NET pages, one for Web
services, and yet another to accommodate .NET Remoting requests for
remote objects hosted by IIS. Other helper handlers are defined to view
the tracing of individual pages in a Web application (trace.axd) and to block requests for prohibited resources such as .config or .asax files. Starting with ASP.NET 2.0, you also find a handler (webresource.axd) to inject assembly resources and script code into pages. In ASP.NET 3.5, the scriptresource.axd handler has been added as a more refined tool to inject script code and AJAX capabilities into Web pages.
You can write custom HTTP
handlers whenever you need ASP.NET to process certain requests in a
nonstandard way. The list of useful things you can do with HTTP handlers
is limited only by your imagination. Through a well-written handler,
you can have your users invoke any sort of functionality via the Web.
For example, you could implement click counters and any sort of image
manipulation, including dynamic generation of images, server-side
caching, or obstructing undesired linking to your images.
Note
An
HTTP handler can either work synchronously or operate in an
asynchronous way. When working synchronously, a handler doesn’t return
until it’s done with the HTTP request. An asynchronous handler, on the
other hand, launches a potentially lengthy process and returns
immediately after. A typical implementation of asynchronous handlers are
asynchronous pages. |
Conventional ISAPI
extensions and filters should be registered within the IIS metabase. In
contrast, HTTP handlers are registered in the web.config
file if you want the handler to participate in the HTTP pipeline
processing of the Web request. In a manner similar to ISAPI extensions,
you can also invoke the handler directly via the URL.
The IHttpHandler Interface
Want to take the splash and dive into HTTP handler programming? Well, your first step is getting the hang of the IHttpHandler
interface. An HTTP handler is just a managed class that implements that
interface. More specifically, a synchronous HTTP handler implements the
IHttpHandler interface; an asynchronous HTTP handler, on the other hand, implements the IHttpAsyncHandler interface. Let’s tackle synchronous handlers first.
The contract of the IHttpHandler interface defines the actions that a handler needs to take to process an HTTP request synchronously.
Members of the IHttpHandler Interface
The IHttpHandler interface defines only two members—ProcessRequest and IsReusable, as shown in Table 1. ProcessRequest is a method, whereas IsReusable is a Boolean property.
Table 1. Members of the IHttpHandler Interface
Member | Description |
---|
IsReusable | This
property gets a Boolean value indicating whether the HTTP runtime can
reuse the current instance of the HTTP handler while serving another
request. |
ProcessRequest | This method processes the HTTP request. |
The IsReusable property on the System.Web.UI.Page class—the most common HTTP handler in ASP.NET—returns false, meaning that a new instance of the HTTP request is needed to serve each new page request. You typically make IsReusable return false
in all situations where some significant processing is required that
depends on the request payload. Handlers used as simple barriers to
filter special requests can set IsReusable to true to save some CPU cycles. I’ll return to this subject with a concrete example in a moment.
The ProcessRequest method has the following signature:
void ProcessRequest(HttpContext context);
It takes the context of
the request as the input and ensures that the request is serviced. In
the case of synchronous handlers, when ProcessRequest returns, the output is ready for forwarding to the client.
A Very Simple HTTP Handler
Again, an HTTP handler is simply a class that implements the IHttpHandler interface. The output for the request is built within the ProcessRequest method, as shown in the following code:
using System.Web;
namespace Core35.Components
{
public class SimpleHandler : IHttpHandler
{
// Override the ProcessRequest method
public void ProcessRequest(HttpContext context)
{
context.Response.Write("<H1>Hello, I'm an HTTP handler</H1>");
}
// Override the IsReusable property
public bool IsReusable
{
get { return true; }
}
}
}
You
need an entry point to be able to call the handler. In this context, an
entry point into the handler’s code is nothing more than an HTTP
endpoint—that is, a public URL. The URL must be a unique name that IIS
and the ASP.NET runtime can map to this code. When registered, the
mapping between an HTTP handler and a Web server resource is established
through the web.config file:
<configuration>
<system.web>
<httpHandlers>
<add verb="*" path="hello.aspx"
type="Core35.Components.SimpleHandler" />
</httpHandlers>
</system.web>
</configuration>
The <httpHandlers> section lists the handlers available for the current application. These settings indicate that SimpleHandler is in charge of handling any incoming requests for an endpoint named hello.aspx. Note that the URL hello.aspx doesn’t have to be a physical resource on the server; it’s simply a public resource identifier. The type attribute references the class and assembly that contains the handler. It’s canonical format is type[,assembly]. You omit the assembly information if the component is defined in the App_Code or other reserved folders.
Note
If you enter the settings shown earlier in the global web.config file, you will register the SimpleHandler component as callable from within all Web applications hosted by the server machine. |
If you invoke the hello.aspx URL, you obtain the results shown in Figure 1.
The
technique discussed here is the quickest and simplest way of putting an
HTTP handler to work, but there is more to know about registration of
HTTP handlers and there are many more options to take advantage of. Now
let’s consider a more complex example of an HTTP handler.